﻿/****************************************************************************
** file: IndustryCamera.h
** brief: 工业相机的支持代码
** Copyright (C) LiYuan
** Author: LiYuan
** E-Mail: 18069211#qq(.)com
** Version 1.0.1
** Last modified: 2019.02.02
** Modified By: LiYuan
****************************************************************************/

#ifndef INDUSTRYCAMERA_H
#define INDUSTRYCAMERA_H

#include <QObject>
#include <QSize>
#include <QString>
#include <QDebug>
#include <QSettings>
#include <QDateTime>
#include <QMutex>
extern "C" {
#include "libavutil/pixfmt.h"
}
#include "CameraCommon/VideoFrame.h"

namespace Qly {

/// CameraImageProcessing class provides an interface for image processing related camera settings
class CAMERA_EXPORT CameraImageProcessing
{
public:
    enum WhiteBalanceMode {
        WhiteBalanceManual = 0,
        WhiteBalanceAutoOnePush = 1,
        WhiteBalanceAutoContinuous = 2};
    enum GainMode{
        GainManual = 0,
        GainAutoOnePush = 1,
        GainAutoContinuous = 2};

    virtual ~CameraImageProcessing() {}
    virtual bool isAvailable() {return true;}

    virtual bool setWhiteBalanceMode(WhiteBalanceMode mode) {return false;}
    virtual bool whiteBalanceMode(WhiteBalanceMode &mode) {return false;}
    virtual bool setManualWhiteBalance(double colorTemperature, double Tint) {return false;}
    virtual bool manualWhiteBalance(double &colorTemperature, double &Tint) {return false;}
    virtual bool setWhiteBalance(int red, int green, int blue) {return false;}
    virtual bool whiteBalance(int &red, int &green, int &blue){return false;}

    virtual bool whiteBalanceRedRange(int &nMin, int &nMax, int &nValue) {return false;}
    virtual bool whiteBalanceGreenRange(int &nMin, int &nMax, int &nValue) {return false;}
    virtual bool whiteBalanceBlueRange(int &nMin, int &nMax, int &nValue) {return false;}

    virtual bool setWhiteBalanceRed(int red) {return false;}
    virtual bool setWhiteBalanceGreen(int green) {return false;}
    virtual bool setWhiteBalanceBlue(int blue){return false;}

    virtual bool setGain(double fValue) {return false;} // >=0 , default is 0
    virtual bool gain(double &fValue) {return false;}
    virtual bool gainRange(double &min, double &max, double &value) {return false;}
    virtual bool setGainMode(GainMode mode) {return false;}
    virtual bool gainMode(GainMode &mode) {return false;}

    virtual bool setBrightness(double value) {return false;}//between -1.0 and 1.0, with a default of 0.
    virtual bool brightness(double &value){return false;} //between -1.0 and 1.0
    virtual bool brightnessEnable(bool &on) {return false;}
    virtual bool setBrightnessEnable(bool on) {return false;}

    virtual bool setGamma(double v){return false;}// > 0, default is 1.0
    virtual bool gamma(double &v) {return false;}
    virtual bool gammaEnable(bool &on) {return false;}
    virtual bool setGammaEnable(bool on) {return false;}
    virtual bool gammaRange(double &min, double &max, double &value) {return false;}

    virtual bool setSharpness(double value) {return false;} //between -1.0 and 1.0, with a default of 0.
    virtual bool sharpness(double &value) {return false;}
    virtual bool sharpnessEnable(bool &on) {return false;}
    virtual bool setSharpnessEnable(bool on) {return false;}

    virtual bool setBlackLevel(double value){return false;} //between -1.0 and 1.0, with a default of 0.
    virtual bool blackLevel(double &value) {return false;}
    virtual bool blackLevelEnable(bool &on) {return false;}
    virtual bool setBlackLevelEnable(bool on) {return false;}

    virtual bool setContrast(double value){return false;} //between -1.0 and 1.0, with a default of 0.
    virtual bool contrast(double &value) {return false;}
    virtual bool contrastEnable(bool &on) {return false;}
    virtual bool setContrastEnable(bool on) {return false;}

    virtual bool setSaturation(double value){return false;} //between -1.0 and 1.0, with a default of 0.
    virtual bool saturation(double &value) {return false;}
    virtual bool saturationEnable(bool &on) {return false;}
    virtual bool setSaturationEnable(bool on) {return false;}

    virtual bool setDenoise(double value){return false;} //between -1.0 and 1.0, with a default of 0.
    virtual bool denoise(double &value) {return false;}
    virtual bool denoiseEnable(bool &on) {return false;}
    virtual bool setDenoiseEnable(bool on) {return false;}

    virtual bool setHue(double value){return false;} //between -1.0 and 1.0, with a default of 0.
    virtual bool hue(double &value) {return false;}
    virtual bool hueEnable(bool &on) {return false;}
    virtual bool setHueEnable(bool on) {return false;}

    virtual bool loadWhiteBalanceSettings(QSettings &settings) {return false;}
    virtual bool writeBalanceSettings(QSettings &settings) {return false;}

    virtual bool loadGainSettings(QSettings &settings) {return false;}
    virtual bool writeGainSettings(QSettings &settings) {return false;}

    virtual bool loadSettings(QSettings &settings){return false;}
    virtual bool writeSettings(QSettings &settings){return false;}
};

/// 工业相机的接口
class CAMERA_EXPORT IndustryCamera : public QObject
{
    Q_OBJECT
public:
    enum AutoExposureMode {OFF, ONCE, CONTINUOUS};
    explicit IndustryCamera(QObject *parent = 0)
    {
        m_imageCount = 0;
        qRegisterMetaType<AVPixelFormat>("AVPixelFormat");
        qRegisterMetaType<VideoFrame>("VideoFrame");
    }
    virtual ~IndustryCamera() {}
    virtual bool isLive() = 0;
signals:
    void imageDataReady(const uint8_t *imgBuf, int stride, QSize size, AVPixelFormat format);
    void videoFrameReady(VideoFrame videoFrame);
    void deviceLost();

public slots:
    // 以下为相机设置的通用接口。除这些接口之外，相机还可以有其他特殊的接口。
    virtual bool openDefaultCamera() = 0;
    virtual bool startGrabbing() = 0; //启动实时视频采集
    virtual bool stopGrabbing() = 0; //停止实时视频采集

    virtual bool setPixelType(AVPixelFormat type) {Q_UNUSED(type);    return false;}

    /**
     * @brief saveSettingsToFile 从文件中加载相机设置参数。
     * 该文件格式为通用格式，并不特定针对某一个相机。因此更换相机后还可以保证新相机的工作参数与旧相机基本一致。
     * 暂时只支持 ini 格式的文件。
     * @param fileName
     */
    virtual bool saveSettingsToFile(QString fileName) {Q_UNUSED(fileName);    return false;}

    /**
     * @brief loadSettingsFromFile 将相机的设置参数保存到文件中。
     * 该文件格式为通用格式，并不特定针对某一个相机。因此更换相机后还可以保证新相机的工作参数与旧相机基本一致。
     * @param fileName
     */
    virtual bool loadSettingsFromFile(QString fileName) {Q_UNUSED(fileName);    return false;}
    virtual void close() = 0; //关闭相机

    virtual bool setExposureTimeMode(AutoExposureMode mode) {Q_UNUSED(mode);    return false;}
    virtual bool exposureTimeMode(AutoExposureMode &mode) {Q_UNUSED(mode);    return false;}
    virtual bool autoExposureTime(bool &on) {Q_UNUSED(on);    return false;}
    virtual bool autoExposureTimeLowerLimitRange(int &nMin, int &nMax, int &nValue) {Q_UNUSED(nValue);     Q_UNUSED(nMin);    Q_UNUSED(nMax);    return false;}
    virtual bool autoExposureTimeUpperLimitRange(int &nMin, int &nMax, int &nValue) {Q_UNUSED(nValue);     Q_UNUSED(nMin);    Q_UNUSED(nMax);    return false;}

    virtual bool setExposureTime(double us) {Q_UNUSED(us);    return false;} //设置曝光时间，单位毫秒
    virtual bool exposureTime(double &us) {Q_UNUSED(us);    return false;}
    virtual bool exposureTimeRange(double &min, double &max, double &us) {Q_UNUSED(us);    Q_UNUSED(min);    Q_UNUSED(max);    return false;}
    virtual bool setFrameRate(double fps) {Q_UNUSED(fps);    return false;} //设置帧率
    virtual bool frameRate(double &fps) {Q_UNUSED(fps);    return false;}

    CameraImageProcessing * imageProcessing() {return m_cameraImageProcessing;}
    virtual bool showVCDPropertyPage() = 0; //打开相机参数设置对话框

    int imageCount() const{return m_imageCount;}
    int newImage(){ return m_imageCount ++;}

    QString deviceName() const {return m_DeviceModelName;}
    QString deviceID() const {return m_DeviceID;}
    QString deviceVendorName() const {return m_DeviceVendorName;}
protected:
    int m_imageCount;
    QString m_DeviceVendorName;
    QString m_DeviceModelName;
    QString m_DeviceManufacturerInfo;
    QString m_DeviceVersion;
    QString m_DeviceFirmwareVersion;
    QString m_DeviceSerialNumber;
    QString m_DeviceID;
    QString m_DeviceUserID;
    QString m_UserID;

    CameraImageProcessing * m_cameraImageProcessing = nullptr;

};

inline QString PixelFormat2QString(AVPixelFormat format)
{
    QString str;
    switch (format) {
    case AV_PIX_FMT_NONE :
        str = "NONE";
        break;
    case AV_PIX_FMT_YUV420P:
        str = "YUV420P";
        break;
    case AV_PIX_FMT_YUYV422:
        str = "YUYV422";
        break;
    case AV_PIX_FMT_UYVY422:
        str = "UYVY422";
        break;
    case AV_PIX_FMT_RGB24:
        str = "RGB24";
        break;
    case AV_PIX_FMT_BGR24:
        str = "BGR24";
        break;
    case AV_PIX_FMT_YUV422P:
        str = "YUV422P";
        break;
    case AV_PIX_FMT_YUV444P:
        str = "YUV444P";
        break;
    case AV_PIX_FMT_YUV410P:
        str = "YUV410P";
        break;
    case AV_PIX_FMT_YUV411P:
        str = "YUV411P";
        break;
    case AV_PIX_FMT_GRAY8:
        str = "GRAY8";
        break;
    case AV_PIX_FMT_ARGB:
        str = "ARGB";
        break;
    case AV_PIX_FMT_RGBA:
        str = "RGBA";
        break;
    case AV_PIX_FMT_ABGR:
        str = "ABGR";
        break;
    case AV_PIX_FMT_BGRA:
        str = "BGRA";
        break;
    case AV_PIX_FMT_BAYER_BGGR8:
        str = "BAYER_BGGR8";
        break;
    case AV_PIX_FMT_BAYER_RGGB8:
        str = "BAYER_RGGB8";
        break;
    case AV_PIX_FMT_BAYER_GRBG8:
        str = "BAYER_GRBG8";
        break;
    case AV_PIX_FMT_BAYER_GBRG8:
        str = "BAYER_GBRG8";
        break;
    case AV_PIX_FMT_BAYER_BGGR16LE:
        str = "BAYER_BGGR16LE";
        break;
    case AV_PIX_FMT_BAYER_RGGB16LE:
        str = "BAYER_RGGB16LE";
        break;
    case AV_PIX_FMT_BAYER_GBRG16LE:
        str = "BAYER_GBRG16LE";
        break;
    case AV_PIX_FMT_BAYER_GRBG16LE:
        str = "BAYER_GRBG16LE";
        break;
    default:
        str = "AV_PIX_FMT_UNKNOWN";
        break;
    }
    return str;
}

inline QDebug operator<<(QDebug dbg, const AVPixelFormat &format)
{
    dbg.nospace() << PixelFormat2QString(format);
    return dbg.maybeSpace();
}



} //namespace Qly

#endif // INDUSTRYCAMERA_H
